Skip to content

🤖 feat: ship generated install bundle and CI freshness checks - #89

Merged
ThomasK33 merged 10 commits into
mainfrom
feat/install-bundle-manifest
Sep 24, 2026
Merged

ThomasK33 merged 10 commits into
mainfrom
feat/install-bundle-manifest

Conversation

@ThomasK33

@ThomasK33 ThomasK33 commented Feb 24, 2026

Copy link
Copy Markdown
Member

Summary

Adds a generated, single-file install bundle, dist/install.yaml, so the operator installs with one kubectl apply. The bundle runs the operator in controller mode only. A CI check keeps the bundle in sync with its sources. The getting-started guide now uses the bundle.

Background

Installing meant applying ten CRD, RBAC and Deployment files one by one. This PR was opened in February and held. Its quickstart path did not converge on repeated apply (#105, since fixed by #116), and its review budget had run out. The maintainer has since extended that budget. The PR has been rebuilt on current main with a reduced scope.

Scope refresh (2026-09-24):

  • Kept: one bundle, dist/install.yaml, the kustomize sources behind it, a freshness check and the getting-started update.
  • Dropped: the duplicate dist/minimal-installer.yaml, which was byte-identical to dist/install.yaml, plus the quickstart manifests (config/quickstart/*, dist/quickstart-installer.yaml). Restoring a supported quickstart is separate follow-up work that depends on 🤖 fix: handle template imports that outlast the request deadline #117.
  • Controller-only (security review of this PR): the bundle no longer contains the aggregated API server's Service and APIService, or the two RBAC bindings only that server uses. config/default/controller-mode-patch.yaml runs the bundled Deployment with --app=controller and drops the container ports that mode does not serve. deploy/deployment.yaml and the per-file manifests are unchanged; the aggregated API server keeps its own how-to.
  • Earlier heads: the previous published head bd2d2e2d and the private candidate are preserved.

Implementation

  • Tooling: kustomize v5.8.1 as a pinned, vendored go tool. This adds seven modules and changes no existing module versions; vendor/ gains only new files.
  • Sources:
    • config/default/kustomization.yaml combines the coder-system namespace, the CRDs, the controller's RBAC and the operator Deployment, patched to --app=controller.
    • hack/update-manifests.sh writes config/default/kustomization.yaml with each CRD and RBAC file listed individually. config/crd/bases/ and config/rbac/ stay free of kustomization files, so the existing kubectl apply -f config/crd/bases/ -f config/rbac/ installs in the README, docs, hack/kind-dev.sh and the E2E keep working. The script stops if a kustomization file appears there. An earlier revision of this refresh broke those installs, and the PR's Kind E2E caught it.
  • Build: make build-installer regenerates dist/install.yaml (write to a temp file, then rename). Two runs are byte-identical.
  • CI: the required lint job regenerates the bundle and fails on any diff or untracked generated file. Enforcement comes from the existing required check, so no branch-protection change is needed. lint now also runs on PRs that change installer inputs.
  • Docs: docs/tutorials/getting-started.md installs from $BASE/dist/install.yaml, in the style of 🤖 refactor: rewrite README and docs for readability #123. It says what the bundle does not install, and it documents a safe cleanup order: control plane first, then the bundle.

Validation

  • Local gates on this head: the freshness step, verify-vendor, build, lint, test, actionlint, docs-check, markdownlint and cspell pass. govulncheck (run on an earlier head with the same go.mod) reports only the known module-level GO-2026-5932. The kustomize modules have no advisories.
  • Freshness check negative controls: a CRD marker changed without regenerating fails; an untracked file under dist/ fails; a new file in config/rbac/ without regenerating fails; the clean tree passes.
  • Directory installs: kubectl apply -f config/e2e/namespace.yaml, -f config/crd/bases/, -f config/rbac/ and the README's combined command succeed on a throwaway KIND cluster. On the previous revision they failed with the same error as CI.
  • The bundle includes the new spec.database.connectionSecretRef field from 🤖 feat: reference the external PostgreSQL Secret from CoderControlPlane #122.
  • Live KIND run of the controller-only bundle (commit 13066a2, dist/install.yaml sha256 1d04b902…). Nothing was pre-applied. The applied copy differs from dist/install.yaml only in the operator image tag and imagePullPolicy, because the image was built from this source and loaded into the cluster.
    1. kubectl apply creates only the Namespace, 3 CRDs, ServiceAccount, ClusterRole, ClusterRoleBinding and Deployment. The pod runs with --app=controller and declares only the health port. The APIService v1alpha1.aggregation.coder.com does not exist.
    2. The tutorial's sample CoderControlPlane reaches Ready, and its Deployment and Service come up.
    3. Uninstalling in the documented order removes the control plane, CRDs, namespaces and cluster RBAC. The cluster, containers and image were deleted afterwards.
  • Earlier run with the full bundle (before this reduction): re-applying the bundle was a no-op and the CloudNativePG example reached Ready with DatabaseSecretResolved=True. Those steps were not repeated on the controller-only bundle.

Live KIND run, controller-only bundle install

Live KIND run, tutorial control plane Ready

Live KIND run, uninstall in the documented order

Accelerated replays of the install and control-plane steps (idle gaps trimmed, so durations are shorter than wall time):

A-install.webm
B-controlplane.webm

Risks

  • Scope: new files, and one changed install path in the tutorial. Existing per-file manifests are unchanged. The bundle installs less than kubectl apply -f deploy/ does: users who want the aggregated API server follow its how-to.
  • Image: the bundle uses the same ghcr.io/coder/coder-k8s:latest image as deploy/deployment.yaml. The tutorial says to pin a release tag and the image for reproducible installs.
  • Size: about 93k vendored lines for kustomize. That follows the repository's vendored-tool pattern and keeps generation reproducible.

Generated with xum • Model: anthropic:claude-opus-5-5 • Thinking: xhigh • Cost: $1622.82

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Please review the installer bundle generation and CI freshness check changes.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d749540f83

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/workflows/ci.yaml Outdated
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Addressed your feedback by diffing full generated CRD and RBAC directories in the freshness check.
Please take another look.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🎉

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Follow-up change: split generated installer output into minimal and quickstart manifests,
with quickstart seeding a template/workspace and CI freshness checks updated accordingly.
Please take another look.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 988d23cd03

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/workflows/ci.yaml Outdated
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Addressed the review comment by making the installer freshness job fail on untracked generated files too.
Please take another look.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Delightful!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ThomasK33

Copy link
Copy Markdown
Member Author

Maintainer status: held

  1. This head (bd2d2e2d) is stale. It predates current main, and the quickstart flow it documents does not converge on repeated apply (tracked in 🤖 fix: make aggregated quickstart creation and repeated apply converge #105).
  2. A reduced-scope candidate exists privately: the minimal installer only, with the generated quickstart example documented as unsupported. It passed local gates and an isolated KIND install/cleanup run on 2026-09-21. It has not been pushed, and it must be refreshed onto current main and revalidated before publication.
  3. Review budget: this PR has used 4 of its 6 lifetime assessments (all normal code reviews; no security review yet). Any refreshed head needs a new normal review, a security review, and an independent final readiness recommendation. That is three assessments with two remaining, and no verified way currently satisfies those gates within two.
  4. Unblock condition: evidence of an assessment mechanism that satisfies every remaining gate within the budget, or an explicit change to the review policy. Until then, no reviews are requested and nothing is pushed. The PR stays open; a replacement PR for the same work would not reset the count.

Owner: maintainer desk. #105 tracks restoring a supported quickstart path.


Generated with xum • Model: anthropic:claude-opus-5-5 • Thinking: xhigh

Part of the PR #89 scope refresh (generated install bundle). Pin
sigs.k8s.io/kustomize/kustomize/v5 v5.8.1 as a go.mod tool so the installer
bundle can be built with "go tool kustomize" from the vendor tree. The
module graph only gains kustomize and its requirements (kustomize api,
cmd/config and kyaml v0.21.1, go-errors v1.4.2, go-gitignore, treeprint
v1.2.0; sergi/go-diff v1.4.0 was already selected and is now listed). No
existing module version changes.

_Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `xhigh`_

Change-Id: I7f7eabd4d9e246debb09df4a46eb564a98fdfd15
Signed-off-by: Thomas Kosiewski <tk@coder.com>
Part of the PR #89 scope refresh. hack/update-manifests.sh now also writes
the kustomization.yaml files for config/crd/bases and config/rbac, and
config/default composes the coder-system namespace, the CRDs, the RBAC, the
operator Deployment and the aggregated API Service and APIService.
"make build-installer" runs the manifest generation and renders
config/default with the vendored kustomize into dist/install.yaml, the
single install bundle for the operator and the aggregated API server. The
minimal and quickstart variants from the earlier PR #89 heads are
intentionally not included.

_Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `xhigh`_

Change-Id: I3214b59ca5f2bdd9efd3d525b3fdc767bca4983f
Signed-off-by: Thomas Kosiewski <tk@coder.com>
Part of the PR #89 scope refresh, adapted to the current ci.yaml. A new
installer-manifest job runs "make build-installer" and fails on any diff in
dist/install.yaml, config/crd/bases or config/rbac, or on untracked files
under those paths. It runs in the merge queue and on changes to Go code,
the manifest inputs, the bundle or this workflow; publish-main waits for it.

_Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `xhigh`_

Change-Id: Ie73e1493152ed070a898d1e5a87fa526db97c2ad
Signed-off-by: Thomas Kosiewski <tk@coder.com>
Part of the PR #89 scope refresh. The tutorial installs the operator and the
aggregated API server with the single dist/install.yaml bundle instead of
applying CRDs, RBAC and the Deployment one by one, and states that the bundle
does not deploy Coder itself. Cleanup deletes the sample control plane first
and then the bundle. The minimal and quickstart installer variants are not
documented.

_Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `xhigh`_

Change-Id: I747a9c08b7486bad564a86f64f526eb29d140310
Signed-off-by: Thomas Kosiewski <tk@coder.com>
Part of the PR #89 scope refresh, after desk review. The separate
installer-manifest job was not a required status check, so a stale
dist/install.yaml could still pass the merge queue. Move the "Verify
installer manifests are up to date" step into the required lint job, right
after the API reference docs check, and run lint on pull requests that
touch installer inputs (the installer path filter) as well as Go code. The
merge queue already always runs lint. publish-main no longer references the
removed job.

_Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `xhigh`_

Change-Id: Id3d099067fa18cce9e63009e279d6725df146cc9
Signed-off-by: Thomas Kosiewski <tk@coder.com>
Part of the PR #89 scope refresh, rebased onto main c942c97. "make
manifests build-installer" picks up spec.database.connectionSecretRef and
its validation rules from the regenerated CoderControlPlane CRD. No other
generated file changed.

_Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `xhigh`_

Change-Id: I6cd893fdad04fa3c352a9e55a01cd480f9153f0f
Signed-off-by: Thomas Kosiewski <tk@coder.com>
@ThomasK33
ThomasK33 force-pushed the feat/install-bundle-manifest branch from bd2d2e2 to 2a11bd7 Compare September 24, 2026 10:03
@ThomasK33

Copy link
Copy Markdown
Member Author

Refreshed and back in review

This PR was rebuilt on current main (2e07c7df) with a reduced scope. The branch was force-pushed with a lease on the previous head bd2d2e2d; that head and the earlier private candidate are preserved.

The description has the details and the KIND validation, installing only through the bundle.


Generated with xum • Model: anthropic:claude-opus-5-5 • Thinking: xhigh • Cost: $1566.03

…tl -f

PR #89's Kind E2E failed at "Apply namespace, CRDs, and RBAC": the
generated config/crd/bases/kustomization.yaml and config/rbac/kustomization.yaml
were picked up by "kubectl apply -f config/crd/bases/" and "-f config/rbac/"
("no matches for kind Kustomization"). README, CONTRIBUTING, several how-to
pages, examples/cloudnativepg and hack/kind-dev.sh apply those directories
the same way.

Remove both files. hack/update-manifests.sh now generates
config/default/kustomization.yaml itself, listing every CRD and RBAC file
individually next to the namespace and deploy manifests, and fails if either
directory contains a kustomization.yaml. The freshness check also covers
config/default. dist/install.yaml is byte-identical to the previous bundle.

_Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `xhigh`_

Change-Id: I0776cd798d2dcf50b47291b15d2b0d3fee9a61c0
Signed-off-by: Thomas Kosiewski <tk@coder.com>
list_manifests ran inside process substitution, so its assertion (for
example a kustomization.yaml in config/rbac/) printed an error but the
script still exited 0 and wrote config/default/kustomization.yaml.
Capture the lists with command substitution so set -e stops the script.
Verified: the negative case now exits 1, and dist/install.yaml is
unchanged (sha256 4fedcc2e...).

Part of the PR #89 scope refresh.

_Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `xhigh`_

Change-Id: Id840489a3ae2bb2c900f0e1c4cde557963917f62
Signed-off-by: Thomas Kosiewski <tk@coder.com>
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

This comment has been minimized.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b2db158db4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread hack/update-manifests.sh
Comment thread docs/tutorials/getting-started.md Outdated
Addresses two findings from the PR #89 review.

controller-gen does not delete CRD YAML for removed or renamed API types,
and update-manifests.sh now enumerates config/crd/bases into config/default
and dist/install.yaml, so a stale CRD would keep shipping. The script now
clears the fully generated config/crd/bases/*.yaml before running
controller-gen. config/rbac also holds hand-written manifests, so only its
generated role.yaml is removed beforehand, and the script fails if
controller-gen does not write it again.

The getting-started prerequisites now list every kind the bundle creates,
including the Service and the apiregistration.k8s.io/v1 APIService.

_Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `xhigh`_

Change-Id: Ib105db926f0ac700da81838b2b5742c6ce23a766
Signed-off-by: Thomas Kosiewski <tk@coder.com>
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex security review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🚀

Reviewed commit: 3fac85b7fc

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛡️ Codex Security Review

Here are some automated security review suggestions for this pull request.

Reviewed commit: 3fac85b7fc

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

Comment thread config/default/kustomization.yaml Outdated
Part of the PR #89 scope refresh: narrow the install bundle to what the
getting-started tutorial needs.

- config/default/controller-mode-patch.yaml runs the bundled Deployment
  with --app=controller and drops the container ports that mode does not
  serve. deploy/deployment.yaml keeps its defaults.
- hack/update-manifests.sh lists the patch in the generated
  config/default/kustomization.yaml and no longer adds the aggregated API
  Service and APIService. It leaves out auth-delegator-binding.yaml and
  authentication-reader-binding.yaml, which only the aggregated API server
  uses; they stay in config/rbac for kubectl apply -f config/rbac/.
- dist/install.yaml now holds the namespace, CRDs, ServiceAccount,
  ClusterRole, ClusterRoleBinding and the controller Deployment.
- getting-started lists those permissions, says the bundle installs the
  operator in controller mode, and links the aggregated API server how-to.

_Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `xhigh`_

Change-Id: I7839947ff2013c74d55d612ab3c612721d9cd121
Signed-off-by: Thomas Kosiewski <tk@coder.com>
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex security review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. More of your lovely PRs please.

Reviewed commit: 13066a2c11

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review

Security review completed. No security issues were found in this pull request.

Reviewed commit: 13066a2c11

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@ThomasK33
ThomasK33 added this pull request to the merge queue Sep 24, 2026
Merged via the queue into main with commit f2a8e81 Sep 24, 2026
31 of 33 checks passed
@ThomasK33
ThomasK33 deleted the feat/install-bundle-manifest branch September 24, 2026 12:09
@ThomasK33

Copy link
Copy Markdown
Member Author

Landed as f2a8e81. The squash tree matched the reviewed head merged onto main, and the merge queue ran the lint job (including the bundle freshness check) and the Kind E2E.

One regression: the Publish GHCR :main job then failed. GoReleaser's release --clean deleted the tracked dist/install.yaml, which left git dirty. #131 moved GoReleaser output to .goreleaser-dist/, and the next main publish succeeded: ghcr.io/coder/coder-k8s:main now carries 330a980 for linux/amd64 and linux/arm64. dist/install.yaml is served from main.


Generated with xum • Model: anthropic:claude-opus-5-5 • Thinking: xhigh

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant